/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import { FileSet } from '@ohos/hvigor';
import fs from 'fs';
import path from 'path';

import { CommonConst, DefaultTargetConst } from '../../const/common-const.js';
import { JsonProfile } from '../../model/json-profile.js';
import { LegacyTargetSourceSetModel } from '../../model/source-set/source-set-model.js';
import { ConfigJson } from '../../options/configure/config-json-options.js';
import { removeLegacyPhoneSupport } from '../../utils/validate/error-handlers.js';
import { ValidateUtil } from '../../utils/validate/validate-util.js';
import { AbstractPreBuild } from '../abstract/abstract-pre-build.js';
import { TaskNames } from '../common/task-names.js';
import { TargetTaskService } from '../service/target-task-service.js';
import ConfigOptObj = ConfigJson.ConfigOptObj;
import LegacyFATask = TaskNames.LegacyFATask;
import fse from 'fs-extra';

import { FileUtil } from '../../utils/file-util.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import CommonTask = TaskNames.CommonTask;
import { hvigorOrToolChainsChanged } from '../../utils/meta-util.js';

const _log = OhosLogger.getLogger('hvigor-legacyPreBuild');

/**
 * Fa module preBuild Task
 *
 * @since 2022/9/8
 */
export class LegacyPreBuild extends AbstractPreBuild {
  // target相关属性
  private readonly targetJsonPath: string;
  private readonly targetConfigOptObj: ConfigOptObj | undefined;
  private logger: OhosLogger = OhosLogger.getLogger(LegacyPreBuild.name);
  private readonly configOptObj: ConfigOptObj;

  declareInputFiles(): FileSet {
    const fileSet = new FileSet().addEntries([this.targetJsonPath], {
      isDirectory: false,
    });
    if (fs.existsSync(path.resolve(this.moduleModel?.getSourceRootByTargetName(this.targetName), CommonConst.SYSCAP_JSON))) {
      fileSet.addEntry(this.syscapJsonPath);
    }

    // 如果对应的oh-package.json5或package.json文件不存在，则不放进输入文件中
    const packageJsonPath = this.isOhpmProject ? this.moduleModel.getOhPackageJson5Path() : this.moduleModel.getPackageJsonPath();
    if (fs.existsSync(packageJsonPath)) {
      fileSet.addEntry(packageJsonPath);
    }
    if (fs.existsSync(this.projectProfilePath)) {
      fileSet.addEntry(this.projectProfilePath);
    }
    if (fs.existsSync(this.profilePath)) {
      fileSet.addEntry(this.profilePath);
    }
    return fileSet;
  }

  constructor(taskService: TargetTaskService) {
    super(taskService, LegacyFATask.PRE_BUILD);

    const targetSourceSetModel: LegacyTargetSourceSetModel = taskService.getTargetData().getModuleSourceSetModel() as LegacyTargetSourceSetModel;
    const targetRes = targetSourceSetModel.getLegacyModuleTargetRes();
    this.targetJsonPath = targetRes.getJsonPath();
    this.targetConfigOptObj = targetRes.getConfigJsonOpt();
    this.configOptObj = fse.readJsonSync(this.targetJsonPath);
  }

  protected doValidateForDiffApiType() {
    const target = this.targetName;
    const configJsonSchemaPath = this.service.hasLiteDevice() ? this.sdkInfo.getLiteSchema() : this.sdkInfo.getRichSchema();
    const configJsonPath = this.targetJsonPath;
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: configJsonPath,
      schemaPath: configJsonSchemaPath,
      errorHandlers: [removeLegacyPhoneSupport],
    });
    this.validateAbilities();
    this.validateForm();
    if (target !== DefaultTargetConst.OHOS_TEST_TARGET) {
      this.validateModuleName(this.moduleName, this.targetConfigOptObj!.module.distro.moduleName, CommonConst.CONFIG_JSON);
    }

    ValidateUtil.validateFALiteDevice(this.configOptObj.module.deviceType);
    ValidateUtil.validateHybridDeviceTypes(this.configOptObj.module.deviceType);
  }

  protected getJsonProfileByModel(): JsonProfile {
    return {
      jsonFilePath: this.targetJsonPath,
      profile: this.configOptObj,
      deviceTypes: this.configOptObj.module.deviceType,
      deviceConfig: CommonConst.DEVICE_TYPE,
      configurationProfile: CommonConst.CONFIG_JSON,
    };
  }

  private validateForm() {
    this.targetConfigOptObj?.module.js?.forEach((jsObj) => {
      if (jsObj.type === 'form') {
        const moduleDir = this.moduleModel.getProjectDir();
        jsObj.pages?.forEach((page) => {
          const formPath = FileUtil.convertToAbsolutePath(page, path.resolve(moduleDir, 'src/main/js', jsObj.name));
          if (!this.isValidWidget(false, '', formPath)) {
            this.logger.printErrorExit(
              'FORM_PAGES_NOT_FOUND',
              [page, this.targetJsonPath],
              [[page], [page]]
            );
          }
        });
      }
    });
  }

  private validateJsType(name: string) {
    this.targetConfigOptObj?.module.js?.forEach((jsObj) => {
      if (jsObj.name === name) {
        switch (jsObj.type) {
          // 外边type是normal，就不去看mode中type, 正常场景,
          case undefined:
            // type缺省时，校验mode中的type，form报错，pageability就正常,
            if (jsObj.mode?.type === 'form') {
              this.logger.printErrorExit(
                'SAME_NAME_BETWEEN_FORM_AND_ABILITY',
                [name, 'module.js.mode', this.targetJsonPath]
              );
            }
            break;
          case 'form':
            // 外边type是form，就不去看mode中type, 直接报错type值不对
            this.logger.printErrorExit(
              'SAME_NAME_BETWEEN_FORM_AND_ABILITY',
              [name, 'module.js', this.targetJsonPath]
            );
            break;
          default:
            break;
        }
      }
    });
  }

  private validateAbilities() {
    // 获取 abilities 中 "type": "page" 的 name.
    // 去js 中找到 name 对应的数据 进行校验
    this.targetConfigOptObj?.module.abilities?.forEach((abilitiesObj) => {
      if (abilitiesObj.type === 'page') {
        const abilitiesName = abilitiesObj.name;
        this.validateJsType(abilitiesName);
      }
    });
  }

  /**
   * AtomicService相关校验
   *
   * @private
   */
  validateAtomicService() {
    // 元服务只支持stage模型
    if (this.isAtomicServiceProject()) {
      _log.printErrorExit('ATOMIC_SERVICE_DOES_NOT_SUPPORT_IN_FA');
    }
  }

  initTaskDepends() {
    hvigorOrToolChainsChanged(this.targetService.getSdkInfo()) && this.dependsOn(CommonTask.CLEAN.name);
  }

  /**
   * 检查差异化的sourceRoot，预留
   */
  protected checkExtendSourceDirs() {
    // empty
  }

  /**
   * 检查byteCodeHar，预留
   */
  protected checkByteCodeHar() {
    // empty
  }

  /**
   * 根据ArkTS1.2的规格进行校验(只在ArkTS1.2下才会执行)，预留
   */
  protected doValidateForStaticArkTS() {
    // empty
  }
}
